

use super::{b2_time::TimeFT, b3_datetime::DateTimeFT, a9_ellapse::EllapseFT, a6_timestamp};



// pub fn sleep_millisecs(start: u64, end: u64) -> u64 {
//     let mut rng = rand::thread_rng();
//     let millis = rng.gen_range(start..end);
//     std::thread::sleep(Duration::from_millis(millis));
//     millis
// }

// pub fn write_utf8(file_text: &str, buf: String) -> String {
//     let mut f = match File::create(file_text) {
//         Ok(v) => v,
//         Err(e) => return format!("write_string: open file {file_text} error: {:?}", e),
//     };
//     match f.write_all(buf.as_bytes()) {
//         Ok(_) => "".to_string(),
//         Err(e) => format!("write_string: write file {file_text} error: {:?}", e),
//     }
// }


// #[test]
// fn test_micros_onesecond_20231022() {
//     let buf = MicrosOneSec::test_generation_print();
//     write_utf8("./test_results/test_micros_onesecond_20231022.txt", buf);
// }

// #[test]
// fn test_secs_oneday_20231022() {
//     let buf = SecsOneDay::test_generation_print();
//     let file_text = "D:/temp/SecsOneDay.test";
//     write_utf8("./test_results/test_secs_oneday_20231022.txt", buf);
// }




#[test]
fn test_time_generation_and_print() {
    let tm1 = TimeFT::from_5_hmsio_unsafe(12, 0, 0, 0, 0);
    for tm2 in vec![TimeFT::from_5_hmsio_unsafe(11, 59, 0, 0, 0),
    TimeFT::from_5_hmsio_unsafe(11, 59, 1, 203, 405),
    TimeFT::from_5_hmsio_unsafe(11, 59, 2, 607, 809),
    TimeFT::from_5_hmsio_unsafe(11, 59, 3, 304, 506),
    TimeFT::from_5_hmsio_unsafe(11, 59, 59, 708, 900)] {
        println!("Testing {tm2:?}:");
        println!("\t{tm2} - {tm1} = {} micros, {} (friendly)", tm2.micros_from(&tm1), tm2.ellapse_string(&tm1));
        println!("\t{tm2} - {tm1} = {:.3} millis ~= {} millis(micro part is omitted by dividing 1000)", tm2.millis_from_f64(&tm1), tm2.millis_from_i32(&tm1));
        println!("\t{tm2} - {tm1} = {:.6} secs", tm2.seconds_from(&tm1));
        println!();
        println!("\t{tm1} - {tm2} = {} micros, {} (friendly)", tm1.micros_from(&tm2), tm1.ellapse_string(&tm2));
        println!("\t{tm1} - {tm2} = {:.3} millis ~= {} millis(micro part is omitted by dividing 1000)", tm1.millis_from_f64(&tm2), tm1.millis_from_i32(&tm2));
        println!("\t{tm1} - {tm2} = {:.6} secs", tm1.seconds_from(&tm2));
        println!();
    }
    /*
Testing TimeFT { display: "11:59:00(000)000", secs: SecsOneDay { print: "11:59:00", inner: 43140 }, micros: 0 }:
        11:59:00(000)000 - 12:00:00(000)000 = -60000000 micros, -60(000)000 (friendly)
        11:59:00(000)000 - 12:00:00(000)000 = -60000.000 millis ~= -60000 millis(micro part is omitted by dividing 1000)
        11:59:00(000)000 - 12:00:00(000)000 = -60.000000 secs

        12:00:00(000)000 - 11:59:00(000)000 = 60000000 micros, 60(000)000 (friendly)
        12:00:00(000)000 - 11:59:00(000)000 = 60000.000 millis ~= 60000 millis(micro part is omitted by dividing 1000)
        12:00:00(000)000 - 11:59:00(000)000 = 60.000000 secs

Testing TimeFT { display: "11:59:01(203)405", secs: SecsOneDay { print: "11:59:01", inner: 43141 }, micros: 203405 }:
        11:59:01(203)405 - 12:00:00(000)000 = -58796595 micros, -59(203)405 (friendly)
        11:59:01(203)405 - 12:00:00(000)000 = -58796.595 millis ~= -58797 millis(micro part is omitted by dividing 1000)
        11:59:01(203)405 - 12:00:00(000)000 = -58.796595 secs

        12:00:00(000)000 - 11:59:01(203)405 = 58796595 micros, 58(796)595 (friendly)
        12:00:00(000)000 - 11:59:01(203)405 = 58796.595 millis ~= 58797 millis(micro part is omitted by dividing 1000)
        12:00:00(000)000 - 11:59:01(203)405 = 58.796595 secs

Testing TimeFT { display: "11:59:02(607)809", secs: SecsOneDay { print: "11:59:02", inner: 43142 }, micros: 607809 }:
        11:59:02(607)809 - 12:00:00(000)000 = -57392191 micros, -58(607)809 (friendly)
        11:59:02(607)809 - 12:00:00(000)000 = -57392.191 millis ~= -57393 millis(micro part is omitted by dividing 1000)
        11:59:02(607)809 - 12:00:00(000)000 = -57.392191 secs

        12:00:00(000)000 - 11:59:02(607)809 = 57392191 micros, 57(392)191 (friendly)
        12:00:00(000)000 - 11:59:02(607)809 = 57392.191 millis ~= 57393 millis(micro part is omitted by dividing 1000)
        12:00:00(000)000 - 11:59:02(607)809 = 57.392191 secs

Testing TimeFT { display: "11:59:03(304)506", secs: SecsOneDay { print: "11:59:03", inner: 43143 }, micros: 304506 }:
        11:59:03(304)506 - 12:00:00(000)000 = -56695494 micros, -57(304)506 (friendly)
        11:59:03(304)506 - 12:00:00(000)000 = -56695.494 millis ~= -56696 millis(micro part is omitted by dividing 1000)
        11:59:03(304)506 - 12:00:00(000)000 = -56.695494 secs

        12:00:00(000)000 - 11:59:03(304)506 = 56695494 micros, 56(695)494 (friendly)
        12:00:00(000)000 - 11:59:03(304)506 = 56695.494 millis ~= 56696 millis(micro part is omitted by dividing 1000)
        12:00:00(000)000 - 11:59:03(304)506 = 56.695494 secs

Testing TimeFT { display: "11:59:59(708)900", secs: SecsOneDay { print: "11:59:59", inner: 43199 }, micros: 708900 }:
        11:59:59(708)900 - 12:00:00(000)000 = -291100 micros, -1(708)900 (friendly)
        11:59:59(708)900 - 12:00:00(000)000 = -291.100 millis ~= -292 millis(micro part is omitted by dividing 1000)
        11:59:59(708)900 - 12:00:00(000)000 = -0.291100 secs

        12:00:00(000)000 - 11:59:59(708)900 = 291100 micros, 00(291)100 (friendly)
        12:00:00(000)000 - 11:59:59(708)900 = 291.100 millis ~= 292 millis(micro part is omitted by dividing 1000)
        12:00:00(000)000 - 11:59:59(708)900 = 0.291100 secs
     */


}
#[test]
fn test_time_le_bytes() {
    let tm1 = TimeFT::from_5_hmsio_unsafe(12, 13, 14, 105, 206);
    println!("Testing {tm1:?}:");
    println!("\t{tm1}.secs_of_day() = {}", tm1.secs_of_day());
    println!("\t{tm1}.micros_of_sec() = {}", tm1.micros_of_sec());
    println!("\t{tm1}.micros_of_day() = {}", tm1.micros_of_day());
    println!("\t{tm1}.hms_friendly() = {}", tm1.hms_friendly());
    println!("\t{tm1}.io_friendly() = {}, (i=milli, o=micro)", tm1.io_friendly());
    println!("\t{tm1}.hmsio_friendly() = {}, (i=milli, o=micro)", tm1.hmsio_friendly());
    println!("\t{tm1}.hour() = {}", tm1.hour());
    println!("\t{tm1}.minute() = {}", tm1.minute());
    println!("\t{tm1}.second() = {}", tm1.second());
    println!("\t{tm1}.milli() = {}", tm1.milli());
    println!("\t{tm1}.micro() = {}", tm1.micro());
    let bts = tm1.to_le_bytes();
    let tm2 = match TimeFT::from_le_bytes(bts) {
        Ok(v) => v,
        Err(e) => panic!("TimeFT::from_le_bytes error:{e:?}"),
    };
    println!("to_le_bytes ok: {tm1} ==> {tm2}");

    let tm3 = TimeFT::from_micros_day_unsafe(tm1.micros_of_day());
    println!("{tm3}: TimeFT::from_micros_day_unsafe(tm1.micros_of_day())");
    let tm4 = TimeFT::from_secs_micros_unsafe(tm1.secs_of_day(), tm1.micros_of_sec());
    println!("{tm4}: TimeFT::from_secs_micros_unsafe(tm1.secs_of_day(), tm1.micros_of_sec()");

    let tm11 = TimeFT::from_hmsi_friendly_unsafe(121314105);
    println!("{tm11}: TimeFT::from_hmsi_friendly_unsafe(121314105)");
    let tm12 = TimeFT::from_hms_io_friendly_unsafe(121314, 105206);
    println!("{tm12}: TimeFT::from_hms_io_friendly_unsafe(121314, 105206)");

    /*
    Testing TimeFT { display: "12:13:14(105)206", secs: SecsOneDay { print: "12:13:14", inner: 43994 }, micros: 105206 }:
        12:13:14(105)206.secs_of_day() = 43994
        12:13:14(105)206.micros_of_sec() = 105206
        12:13:14(105)206.micros_of_day() = 43994105206
        12:13:14(105)206.hms_friendly() = 121314
        12:13:14(105)206.io_friendly() = 105206, (i=milli, o=micro)
        12:13:14(105)206.hmsio_friendly() = 121314105206, (i=milli, o=micro)
        12:13:14(105)206.hour() = 12
        12:13:14(105)206.minute() = 13
        12:13:14(105)206.second() = 14
        12:13:14(105)206.milli() = 105
        12:13:14(105)206.micro() = 206
        12:13:14(105)206 ==> 12:13:14(105)20
     */

}



// #[tokio::test]
// pub async fn test_datetime_highconcurrency() {
//     static statis: Lazy<Statis> = Lazy::new(|| fast_able::statis::Statis::new(|c| println!("一秒并发： {c}") ));
//     let mut arr_rt = vec![];
//     for _ in 0..10{
//         let join = tokio::task::spawn_blocking(|| {
//             for _ in 0..100000_0000{
//                 DateTimeFT::now();
//                 statis.add();
//             }
//         });
//         arr_rt.push(join);
//     }
//     arr_rt.remove(0).await.expect("msg");
// }

// #[cfg(test)]
// #[tokio::test]
// pub async fn run_high_chrono() {
//     static statis: Lazy<Statis> = Lazy::new(|| fast_able::statis::Statis::new(|c| println!("一秒并发： {c}") ));
//     let mut arr_rt = vec![];
//     for _ in 0..10{
//         let join = tokio::task::spawn_blocking(|| {
//             for _ in 0..100000_0000{
//                 chrono::Local::now();
//                 statis.add();
//             }
//         });
//         arr_rt.push(join);
//     }
//     arr_rt.remove(0).await.expect("msg");
// }

fn check_by_micros(dt_now: &DateTimeFT, dt_before: &DateTimeFT) {

    println!("\tCompare dt_now={}, dt_before={}", dt_now.to_print(), dt_before.to_print());
    let micros_timestamp = dt_now.micro_from(dt_before);
    let micros_time = dt_now.time.micros_from(&dt_before.time);
    assert_eq!(micros_timestamp, micros_time);
    let ellase_plus = EllapseFT::new(micros_time);
    let ellase_minus = EllapseFT::new(-micros_time);
    println!("\tellase: {}, {}", ellase_plus.to_print_friendly(), ellase_plus.to_print_exactly());
    println!("\tellase(minus, only for test): {}, {}", ellase_minus.to_print_friendly(), ellase_minus.to_print_exactly());
    
}

#[test]
fn test_datetime_generation_friendly_also_have_ellapse() {
    let yyyymmdd = a6_timestamp::BASIC_INFO_STARTUP.date.ymd_friendly() as u32;
    let hhmmss = 12_34_56_u32;
    let iiiooo = 708901_u32;
    
    let yyyymmdd_hhmmss = yyyymmdd as u64 * 1_000000 + hhmmss as u64;

    let dt_now = DateTimeFT::now();
    {
        let dt_before = DateTimeFT::from_ymd_friendly_unsafe(yyyymmdd);
        println!("\n====== Testing 1. DateTimeFT::from_ymd_friendly_unsafe:");
        println!("\t{yyyymmdd}_u32 ==> {}", dt_before.to_print());
        check_by_micros(&dt_now, &dt_before);
    }
    {
        let dt_before = DateTimeFT::from_ymd_hms_friendly_unsafe(yyyymmdd, hhmmss);
        println!("\n====== Testing 2. DateTimeFT::from_ymd_hms_friendly_unsafe:");
        println!("\t{yyyymmdd}_u32, 12_34_56_u32 ==> {}", dt_before.to_print());
        check_by_micros(&dt_now, &dt_before);
    }
    {
        let dt_before = DateTimeFT::from_ymd_hms_io_friendly_unsafe(yyyymmdd, hhmmss, iiiooo);
        println!("\n====== Testing 3. DateTimeFT::from_ymd_hms_io_friendly_unsafe:");
        println!("\t{yyyymmdd}_u32, 12_34_56_u32, 708901_u32==> {}, ", dt_before.to_print());
        check_by_micros(&dt_now, &dt_before);
    }
    
    {
        let dt_before = DateTimeFT::from_14_ymdhms_friendly_unsafe(yyyymmdd_hhmmss);
        println!("\n====== Testing 4. DateTimeFT::from_14_ymdhms_friendly_unsafe:");
        println!("\t{yyyymmdd}_123456_u64(14 digitals)  ==> {},", dt_before.to_print());
        check_by_micros(&dt_now, &dt_before);
    }

    {
        let yyyymmdd_hhmmss_iii = yyyymmdd as u64 * 1_000000_000 + hhmmss as u64 * 1_000 + iiiooo as u64 / 1_000;
        let dt_before = DateTimeFT::from_17_ymdhmsi_friendly_unsafe(yyyymmdd_hhmmss_iii);
        println!("\n====== Testing 5. DateTimeFT::from_17_ymdhmsi_friendly_unsafe:");
        println!("\t{yyyymmdd}_123456_708_u64(17 digitals)  ==> {},", dt_before.to_print());
        check_by_micros(&dt_now, &dt_before);
    }
    {
        let dt_before = DateTimeFT::from_20_ymdhmsio_friendly_unsafe(yyyymmdd_hhmmss, iiiooo);
        // u64::MAX = 1844_6744_0737_0955_1615, i64::MIN = 922_3372_0368_5477_5807: only support 19 digitals.
        // println!("u64::MAX = {}, i64::MIN = {}: only support 19 digitals.", u64::MAX, i64::MAX);
        println!("====== Testing 6. DateTimeFT::from_20_ymdhmsio_friendly_unsafe:");
        println!("\t{yyyymmdd}_123456_u64, 708901_u32(14 + 6 = 20 digitals)  ==> {},", dt_before.to_print());
        check_by_micros(&dt_now, &dt_before);
    }

}

#[test]
fn test_performance_comparison_between_std_and_chrono() {
    use super::test_suites;
    let mut count = 0;
    let fmt = "%H:%M:%S%.6f";

    let mut list_std = Vec::with_capacity(200);
    let mut list_chrono = Vec::with_capacity(200);

    let start = DateTimeFT::now();

    for _ in 0..160 {
        list_std.push(DateTimeFT::now());
    }

    for _ in 0..160 {
        list_chrono.push(chrono::Local::now());
    }

    let start_str = start.to_print();
    info!("datetime_wall::run_test start: {start_str}");

    for item in list_std.iter() {
        info!("\t1. 连续获取【标准库】 {};", item.to_print());
    }
    for item in list_chrono.iter() {
        info!("\t2. 连续获取【chrono】 {};", item.format(fmt).to_string());
    }

    let mut list_std = Vec::with_capacity(200);
    let mut list_chrono = Vec::with_capacity(200);
    for _ in 0..160 {
        list_std.push(DateTimeFT::now());
        list_chrono.push(chrono::Local::now());
    }

    for idx in 0..160 {
        info!(
            "\t1. 连续交替获取:【标准库】  {};",
            list_std.get(idx).unwrap().to_print()
        );
        info!(
            "\t2. 连续交替获取:【chrono】 {};",
            list_chrono.get(idx).unwrap().format(fmt).to_string()
        );
    }

    println!("looping...");
    loop {
        count += 1;
        if count % 1000 == 0 {
            info!(
                "datetime_wall::run_test start: {} 千次, {start_str}",
                count / 1000
            );
        }
        // let millis = test_suites::sleep_millisecs(1000, 2000);
        let millis = 2000;
        let now = DateTimeFT::now();
        let now_chrono = chrono::Local::now();
        let str_chrono = now_chrono.format(fmt).to_string();
        info!(
            "\t1. sleep {millis} millis 先【标准库】后【chrono】: {}; chrono {str_chrono}",
            now.to_print()
        );

        // let millis = test_suites::sleep_millisecs(1000, 2000);
        let now_chrono = chrono::Local::now();
        let now = DateTimeFT::now();
        let str_chrono = now_chrono.format(fmt).to_string();
        info!(
            "\t\t2. sleep {millis} millis 先【chrono】后【标准库】: chrono {str_chrono}; {}",
            now.to_print()
        );
    }
}

#[test]
fn test_performance_comparison_between_std_and_chrono_original() {
    // let utc = Utc::now();

    use super::u3_native::SystemTime;
    let 今日 = "2023-10-22";
    // let date_今日0点 = NaiveDateTime::from_str(&format!("{今日}T00:00:00")).expect("Unreachable");

    let h8小时 = 28800_000_000_i64;
    // let 时间戳_今日0点_chrono = date_今日0点.micros_since_unix_epoch();
    println!("实验二：【先rust原生库_再chrono库】");
    for i in 1..11 {
        println!("第 {i} 次微秒级时间戳测试 {今日} ====================");

        let 时间戳_system_B = SystemTime::now()
            .duration_since(SystemTime::UNIX_EPOCH)
            .unwrap()
            .as_micros() as i64
            + h8小时;

        let date_chrono_C = chrono::Local::now().naive_local();
        let 时间戳_chrono_C = date_chrono_C.timestamp_micros();

        let 时间戳_system_D = SystemTime::now()
            .duration_since(SystemTime::UNIX_EPOCH)
            .unwrap()
            .as_micros() as i64
            + h8小时;

        let date_chrono_E = chrono::Local::now().naive_local();
        let 时间戳_chrono_E = date_chrono_E.timestamp_micros();

        let fmt = "%Y-%m-%d %H:%M:%s";
        let dfmt = date_chrono_C.format(fmt).to_string();
        println!("时间戳_chrono_C: {dfmt}");
        let dfmt = date_chrono_E.format(fmt).to_string();
        println!("时间戳_chrono_E: {dfmt}");
        println!(
            "\t{i}-1. 时间戳_chrono_C - 时间戳_system_B = {}",
            时间戳_chrono_C - 时间戳_system_B
        );
        println!(
            "\t{i}-2. 时间戳_system_D - 时间戳_chrono_C = {}",
            时间戳_system_D - 时间戳_chrono_C
        );
        println!(
            "\t{i}-3. 时间戳_chrono_E - 时间戳_chrono_A = {}",
            时间戳_chrono_E - 时间戳_system_D
        );
        /*
        实验二：rust原生库先获取，再chrono库获取
        （结果类同【实验一】）
        chrono库：
        1. 首次获取时间长，约330微秒+；
        （我们程序中，一般不会持续获取，所以一般都是首次获取）
        2. 第2次及以后获取时间短，约6-16微秒+

        rust原生库：
        1. 获取时间稳定，约 0-1微秒


                实验二：【先rust原生库_再chrono库】
        第 1 次微秒级时间戳测试 2023-09-14 ====================
                1-1. 时间戳_chrono_C - 时间戳_system_B = 9
                1-2. 时间戳_system_D - 时间戳_chrono_C = 333
                1-3. 时间戳_chrono_E - 时间戳_chrono_A = 1
        第 2 次微秒级时间戳测试 2023-09-14 ====================
                2-1. 时间戳_chrono_C - 时间戳_system_B = 1
                2-2. 时间戳_system_D - 时间戳_chrono_C = 16
                2-3. 时间戳_chrono_E - 时间戳_chrono_A = 0
        第 3 次微秒级时间戳测试 2023-09-14 ====================
                3-1. 时间戳_chrono_C - 时间戳_system_B = 1
                3-2. 时间戳_system_D - 时间戳_chrono_C = 8
                3-3. 时间戳_chrono_E - 时间戳_chrono_A = 0
        第 4 次微秒级时间戳测试 2023-09-14 ====================
                4-1. 时间戳_chrono_C - 时间戳_system_B = 0
                4-2. 时间戳_system_D - 时间戳_chrono_C = 7
                4-3. 时间戳_chrono_E - 时间戳_chrono_A = 0
        第 5 次微秒级时间戳测试 2023-09-14 ====================
                5-1. 时间戳_chrono_C - 时间戳_system_B = 0
                5-2. 时间戳_system_D - 时间戳_chrono_C = 16
                5-3. 时间戳_chrono_E - 时间戳_chrono_A = 1
        第 6 次微秒级时间戳测试 2023-09-14 ====================
                6-1. 时间戳_chrono_C - 时间戳_system_B = 0
                6-2. 时间戳_system_D - 时间戳_chrono_C = 16
                6-3. 时间戳_chrono_E - 时间戳_chrono_A = 0
        第 7 次微秒级时间戳测试 2023-09-14 ====================
                7-1. 时间戳_chrono_C - 时间戳_system_B = 0
                7-2. 时间戳_system_D - 时间戳_chrono_C = 16
                7-3. 时间戳_chrono_E - 时间戳_chrono_A = 0
        第 8 次微秒级时间戳测试 2023-09-14 ====================
                8-1. 时间戳_chrono_C - 时间戳_system_B = 0
                8-2. 时间戳_system_D - 时间戳_chrono_C = 14
                8-3. 时间戳_chrono_E - 时间戳_chrono_A = 1
        第 9 次微秒级时间戳测试 2023-09-14 ====================
                9-1. 时间戳_chrono_C - 时间戳_system_B = 0
                9-2. 时间戳_system_D - 时间戳_chrono_C = 15
                9-3. 时间戳_chrono_E - 时间戳_chrono_A = 0
        第 10 次微秒级时间戳测试 2023-09-14 ====================
                10-1. 时间戳_chrono_C - 时间戳_system_B = 0
                10-2. 时间戳_system_D - 时间戳_chrono_C = 9
                10-3. 时间戳_chrono_E - 时间戳_chrono_A = 0
                 */
    }
}

